home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / indentsr / indent.c < prev    next >
C/C++ Source or Header  |  1990-01-04  |  36KB  |  1,186 lines

  1. /*
  2.  * Copyright (c) 1985 Sun Microsystems, Inc.
  3.  * Copyright (c) 1980 The Regents of the University of California.
  4.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by the University of California, Berkeley, the University of Illinois,
  13.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  14.  * or Sun Microsystems may not be used to endorse or promote products
  15.  * derived from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. char copyright[] =
  23. "@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\
  24.  @(#) Copyright (c) 1980 The Regents of the University of California.\n\
  25.  @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\
  26.  All rights reserved.\n";
  27. #endif /* not lint */
  28.  
  29. #ifndef lint
  30. static char sccsid[] = "@(#)indent.c    5.11 (Berkeley) 9/15/88";
  31. #endif /* not lint */
  32.  
  33. #include "indent_globs.h"
  34. #include "indent_codes.h"
  35.  
  36. #ifndef MSDOS
  37. #include <sys/param.h>
  38. #else
  39. #define MAXPATHLEN 64
  40. #endif
  41.  
  42. #include <ctype.h>
  43.  
  44. char       *in_name = "Standard Input";    /* will always point to name of input
  45.                      * file */
  46. char       *out_name = "Standard Output";    /* will always point to name
  47.                          * of output file */
  48. char        bakfile[MAXPATHLEN] = "", tmpstr[MAXPATHLEN] = "";
  49.  
  50. main(argc, argv)
  51.     int         argc;
  52.     char      **argv;
  53. {
  54.  
  55.     extern int  found_err;    /* flag set in diag() on error */
  56.     int         dec_ind;    /* current indentation for declarations */
  57.     int         di_stack[20];    /* a stack of structure indentation levels */
  58.     int         flushed_nl;    /* used when buffering up comments to remember
  59.                  * that a newline was passed over */
  60.     int         force_nl;    /* when true, code must be broken */
  61.     int         hd_type;    /* used to store type of stmt for if (...),
  62.                  * for (...), etc */
  63.     register int i;        /* local loop counter */
  64.     int         scase;        /* set to true when we see a case, so we will
  65.                  * know what to do with the following colon */
  66.     int         sp_sw;        /* when true, we are in the expressin of
  67.                  * if(...), while(...), etc. */
  68.     int         squest;        /* when this is positive, we have seen a ?
  69.                  * without the matching : in a <c>?<s>:<s>
  70.                  * construct */
  71.     register char *t_ptr;    /* used for copying tokens */
  72.     int         type_code;    /* the type of token, returned by lexi */
  73.  
  74.     int         last_else = 0;    /* true iff last keyword was an else */
  75.  
  76.  
  77.     /*-----------------------------------------------*\
  78.     |              INITIALIZATION              |
  79.     \*-----------------------------------------------*/
  80.  
  81.  
  82.     ps.p_stack[0] = stmt;    /* this is the parser's stack */
  83.     ps.last_nl = true;        /* this is true if the last thing scanned was
  84.                  * a newline */
  85.     ps.last_token = semicolon;
  86.     combuf = (char *) malloc(bufsize);
  87.     labbuf = (char *) malloc(bufsize);
  88.     codebuf = (char *) malloc(bufsize);
  89.     l_com = combuf + bufsize - 5;
  90.     l_lab = labbuf + bufsize - 5;
  91.     l_code = codebuf + bufsize - 5;
  92.     combuf[0] = codebuf[0] = labbuf[0] = ' ';    /* set up code, label, and
  93.                          * comment buffers */
  94.     combuf[1] = codebuf[1] = labbuf[1] = '\0';
  95.     ps.else_if = 1;        /* Default else-if special processing to on */
  96.     s_lab = e_lab = labbuf + 1;
  97.     s_code = e_code = codebuf + 1;
  98.     s_com = e_com = combuf + 1;
  99.  
  100.     buf_ptr = buf_end = in_buffer;
  101.     line_no = 1;
  102.     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
  103.     sp_sw = force_nl = false;
  104.     ps.in_or_st = false;
  105.     ps.bl_line = true;
  106.     dec_ind = 0;
  107.     di_stack[ps.dec_nest = 0] = 0;
  108.     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
  109.  
  110.  
  111.     scase = ps.pcase = false;
  112.     squest = 0;
  113.     sc_end = 0;
  114.     bp_save = 0;
  115.     be_save = 0;
  116.  
  117.     output = 0;
  118.  
  119.  
  120.  
  121.     /*--------------------------------------------------*\
  122.     |           COMMAND LINE SCAN         |
  123.     \*--------------------------------------------------*/
  124.  
  125. #ifdef undef
  126.     max_col = 78;        /* -l78 */
  127.     lineup_to_parens = 1;    /* -lp */
  128.     ps.ljust_decl = 0;        /* -ndj */
  129.     ps.com_ind = 33;        /* -c33 */
  130.     star_comment_cont = 1;    /* -sc */
  131.     ps.ind_size = 8;        /* -i8 */
  132.     verbose = 0;
  133.     ps.decl_indent = 16;    /* -di16 */
  134.     ps.indent_parameters = 1;    /* -ip */
  135.     ps.decl_com_ind = 0;    /* if this is not set to some positive value
  136.                  * by an arg, we will set this equal to
  137.                  * ps.com_ind */
  138.     btype_2 = 1;        /* -br */
  139.     cuddle_else = 1;        /* -ce */
  140.     ps.unindent_displace = 0;    /* -d0 */
  141.     ps.case_indent = 0;        /* -cli0 */
  142.     format_col1_comments = 1;    /* -fc1 */
  143.     procnames_start_line = 1;    /* -psl */
  144.     proc_calls_space = 0;    /* -npcs */
  145.     comment_delimiter_on_blankline = 1;    /* -cdb */
  146.     ps.leave_comma = 1;        /* -nbc */
  147. #endif
  148.  
  149.     for (i = 1; i < argc; ++i)
  150.     if (strcmp(argv[i], "-npro") == 0)
  151.         break;
  152.     set_defaults();
  153.     if (i >= argc)
  154.     set_profile();
  155.  
  156.     for (i = 1; i < argc; ++i) {
  157.  
  158.     /*
  159.      * look thru args (if any) for changes to defaults
  160.      */
  161.     if (argv[i][0] != '-') {/* no flag on parameter */
  162.         if (input == 0) {    /* we must have the input file */
  163.         in_name = argv[i];    /* remember name of input file */
  164.         input = fopen(in_name, "r");
  165.         if (input == 0) {    /* check for open error */
  166.             fprintf(stderr, "indent: can't open %s\n", argv[i]);
  167.             exit(1);
  168.         }
  169.         continue;
  170.         }
  171.         else if (output == 0) {    /* we have the output file */
  172.         out_name = argv[i];    /* remember name of output file */
  173.         if (strcmp(in_name, out_name) == 0) {    /* attempt to overwrite
  174.                              * the file */
  175.             fprintf(stderr, "indent: input and output files must be different\n");
  176.             exit(1);
  177.         }
  178.         output = fopen(out_name, "w");
  179.         if (output == 0) {    /* check for create error */
  180.             fprintf(stderr, "indent: can't create %s\n", argv[i]);
  181.             exit(1);
  182.         }
  183.         continue;
  184.         }
  185.         fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
  186.         exit(1);
  187.     }
  188.     else
  189.         set_option(argv[i]);
  190.     }                /* end of for */
  191.     if (input == 0) {
  192.     fprintf(stderr, "indent: usage: indent file [ outfile ] [ options ]\n");
  193.     exit(1);
  194.     }
  195.     if (output == 0)
  196.     if (troff)
  197.         output = stdout;
  198.     else {
  199.         out_name = in_name;
  200.         bakcopy();
  201.     }
  202.     if (ps.com_ind <= 1)
  203.     ps.com_ind = 2;        /* dont put normal comments before column 2 */
  204.     if (troff) {
  205.     if (bodyf.font[0] == 0)
  206.         parsefont(&bodyf, "R");
  207.     if (scomf.font[0] == 0)
  208.         parsefont(&scomf, "I");
  209.     if (blkcomf.font[0] == 0)
  210.         blkcomf = scomf, blkcomf.size += 2;
  211.     if (boxcomf.font[0] == 0)
  212.         boxcomf = blkcomf;
  213.     if (stringf.font[0] == 0)
  214.         parsefont(&stringf, "L");
  215.     if (keywordf.font[0] == 0)
  216.         parsefont(&keywordf, "B");
  217.     writefdef(&bodyf, 'B');
  218.     writefdef(&scomf, 'C');
  219.     writefdef(&blkcomf, 'L');
  220.     writefdef(&boxcomf, 'X');
  221.     writefdef(&stringf, 'S');
  222.     writefdef(&keywordf, 'K');
  223.     }
  224.     if (block_comment_max_col <= 0)
  225.     block_comment_max_col = max_col;
  226.     if (ps.decl_com_ind <= 0)    /* if not specified by user, set this */
  227.     ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
  228.     if (continuation_indent == 0)
  229.     continuation_indent = ps.ind_size;
  230.     fill_buffer();        /* get first batch of stuff into input buffer */
  231.  
  232.     parse(semicolon);
  233.     {
  234.     register char *p = buf_ptr;
  235.     register    col = 1;
  236.  
  237.     while (1) {
  238.         if (*p == ' ')
  239.         col++;
  240.         else if (*p == '\t')
  241.         col = ((col - 1) & ~7) + 9;
  242.         else
  243.         break;
  244.         p++;
  245.     };
  246.     if (col > ps.ind_size)
  247.         ps.ind_level = ps.i_l_follow = col / ps.ind_size;
  248.     }
  249.     if (troff) {
  250.     register char *p = in_name,
  251.                *beg = in_name;
  252.  
  253.     while (*p)
  254.         if (*p++ == '/')
  255.         beg = p;
  256.     fprintf(output, ".Fn \"%s\"\n", beg);
  257.     }
  258.     /*
  259.      * START OF MAIN LOOP
  260.      */
  261.  
  262.     while (1) {            /* this is the main loop.  it will go until we
  263.                  * reach eof */
  264.     int         is_procname;
  265.  
  266.     type_code = lexi();    /* lexi reads one token.  The actual
  267.                  * characters read are stored in "token". lexi
  268.                  * returns a code indicating the type of token */
  269.     is_procname = ps.procname[0];
  270.  
  271.     /*
  272.      * The following code moves everything following an if (), while (),
  273.      * else, etc. up to the start of the following stmt to a buffer. This
  274.      * allows proper handling of both kinds of brace placement.
  275.      */
  276.  
  277.     flushed_nl = false;
  278.     while (ps.search_brace) {    /* if we scanned an if(), while(),
  279.                      * etc., we might need to copy stuff
  280.                      * into a buffer we must loop, copying
  281.                      * stuff into save_com, until we find
  282.                      * the start of the stmt which follows
  283.                      * the if, or whatever */
  284.         switch (type_code) {
  285.         case newline:
  286.         ++line_no;
  287.         flushed_nl = true;
  288.         case form_feed:
  289.         break;        /* form feeds and newlines found here will be
  290.                  * ignored */
  291.  
  292.         case lbrace:    /* this is a brace that starts the compound
  293.                  * stmt */
  294.         if (sc_end == 0) {    /* ignore buffering if a comment wasnt
  295.                      * stored up */
  296.             ps.search_brace = false;
  297.             goto check_type;
  298.         }
  299.         if (btype_2) {
  300.             save_com[0] = '{';    /* we either want to put the brace
  301.                      * right after the if */
  302.             goto sw_buffer;    /* go to common code to get out of
  303.                      * this loop */
  304.         }
  305.         case comment:    /* we have a comment, so we must copy it into
  306.                  * the buffer */
  307.         if (!flushed_nl || sc_end != 0) {
  308.             if (sc_end == 0) {    /* if this is the first comment, we
  309.                      * must set up the buffer */
  310.             save_com[0] = save_com[1] = ' ';
  311.             sc_end = &(save_com[2]);
  312.             }
  313.             else {
  314.             *sc_end++ = '\n';    /* add newline between
  315.                          * comments */
  316.             *sc_end++ = ' ';
  317.             --line_no;
  318.             }
  319.             *sc_end++ = '/';    /* copy in start of comment */
  320.             *sc_end++ = '*';
  321.  
  322.             for (;;) {    /* loop until we get to the end of the comment */
  323.             *sc_end = *buf_ptr++;
  324.             if (buf_ptr >= buf_end)
  325.                 fill_buffer();
  326.  
  327.             if (*sc_end++ == '*' && *buf_ptr == '/')
  328.                 break;    /* we are at end of comment */
  329.  
  330.             if (sc_end >= &(save_com[sc_size])) {    /* check for temp buffer
  331.                                  * overflow */
  332.                 diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
  333.                 fflush(output);
  334.                 exit(1);
  335.             }
  336.             }
  337.             *sc_end++ = '/';    /* add ending slash */
  338.             if (++buf_ptr >= buf_end)    /* get past / in buffer */
  339.             fill_buffer();
  340.             break;
  341.         }
  342.         default:        /* it is the start of a normal statment */
  343.         if (flushed_nl)    /* if we flushed a newline, make sure it is
  344.                  * put back */
  345.             force_nl = true;
  346.         if (type_code == sp_paren && *token == 'i'
  347.             && last_else && ps.else_if
  348.             || type_code == sp_nparen && *token == 'e'
  349.             && e_code != s_code && e_code[-1] == '}')
  350.             force_nl = false;
  351.  
  352.         if (sc_end == 0) {    /* ignore buffering if comment wasnt
  353.                      * saved up */
  354.             ps.search_brace = false;
  355.             goto check_type;
  356.         }
  357.         if (force_nl) {    /* if we should insert a nl here, put it into
  358.                  * the buffer */
  359.             force_nl = false;
  360.             --line_no;    /* this will be re-increased when the nl is
  361.                  * read from the buffer */
  362.             *sc_end++ = '\n';
  363.             *sc_end++ = ' ';
  364.             if (verbose && !flushed_nl)    /* print error msg if the line
  365.                          * was not already broken */
  366.             diag(0, "Line broken");
  367.             flushed_nl = false;
  368.         }
  369.         for (t_ptr = token; *t_ptr; ++t_ptr)
  370.             *sc_end++ = *t_ptr;    /* copy token into temp buffer */
  371.         ps.procname[0] = 0;
  372.  
  373.     sw_buffer:
  374.         ps.search_brace = false;    /* stop looking for start of
  375.                          * stmt */
  376.         bp_save = buf_ptr;    /* save current input buffer */
  377.         be_save = buf_end;
  378.         buf_ptr = save_com;    /* fix so that subsequent calls to
  379.                      * lexi will take tokens out of
  380.                      * save_com */
  381.         *sc_end++ = ' ';/* add trailing blank, just in case */
  382.         buf_end = sc_end;
  383.         sc_end = 0;
  384.         break;
  385.         }            /* end of switch */
  386.         if (type_code != 0)    /* we must make this check, just in case there
  387.                  * was an unexpected EOF */
  388.         type_code = lexi();    /* read another token */
  389.         /* if (ps.search_brace) ps.procname[0] = 0; */
  390.         if ((is_procname = ps.procname[0]) && flushed_nl
  391.             && !procnames_start_line && ps.in_decl
  392.             && type_code == ident)
  393.         flushed_nl = 0;
  394.     }            /* end of while (search_brace) */
  395.     last_else = 0;
  396. check_type:
  397.     if (type_code == 0) {    /* we got eof */
  398.         if (s_lab != e_lab || s_code != e_code
  399.             || s_com != e_com)    /* must dump end of line */
  400.         dump_line();
  401.         if (ps.tos > 1)    /* check for balanced braces */
  402.         diag(1, "Stuff missing from end of file.");
  403.  
  404.         if (verbose) {
  405.         printf("There were %d output lines and %d comments\n",
  406.                ps.out_lines, ps.out_coms);
  407.         printf("(Lines with comments)/(Lines with code): %6.3f\n",
  408.                (1.0 * ps.com_lines) / code_lines);
  409.         }
  410.         fflush(output);
  411.         exit(found_err);
  412.     }
  413.     if (
  414.         (type_code != comment) &&
  415.         (type_code != newline) &&
  416.         (type_code != preesc) &&
  417.         (type_code != form_feed)) {
  418.         if (force_nl &&
  419.             (type_code != semicolon) &&
  420.             (type_code != lbrace || !btype_2)) {
  421.         /* we should force a broken line here */
  422.         if (verbose && !flushed_nl)
  423.             diag(0, "Line broken");
  424.         flushed_nl = false;
  425.         dump_line();
  426.         ps.want_blank = false;    /* dont insert blank at line start */
  427.         force_nl = false;
  428.         }
  429.         ps.in_stmt = true;    /* turn on flag which causes an extra level of
  430.                  * indentation. this is turned off by a ; or
  431.                  * '}' */
  432.         if (s_com != e_com) {    /* the turkey has embedded a comment
  433.                      * in a line. fix it */
  434.         *e_code++ = ' ';
  435.         for (t_ptr = s_com; *t_ptr; ++t_ptr) {
  436.             check_size(code);
  437.             *e_code++ = *t_ptr;
  438.         }
  439.         *e_code++ = ' ';
  440.         *e_code = '\0';    /* null terminate code sect */
  441.         ps.want_blank = false;
  442.         e_com = s_com;
  443.         }
  444.     }
  445.     else if (type_code != comment)    /* preserve force_nl thru a comment */
  446.         force_nl = false;    /* cancel forced newline after newline, form
  447.                  * feed, etc */
  448.  
  449.  
  450.  
  451.     /*-----------------------------------------------------*\
  452.     |       do switch on type of token scanned        |
  453.     \*-----------------------------------------------------*/
  454.     check_size(code);
  455.     switch (type_code) {    /* now, decide what to do with the token */
  456.  
  457.     case form_feed:    /* found a form feed in line */
  458.         ps.use_ff = true;    /* a form feed is treated much like a newline */
  459.         dump_line();
  460.         ps.want_blank = false;
  461.         break;
  462.  
  463.     case newline:
  464.         if (ps.last_token != comma || ps.p_l_follow > 0
  465.             || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
  466.         dump_line();
  467.         ps.want_blank = false;
  468.         }
  469.         ++line_no;        /* keep track of input line number */
  470.         break;
  471.  
  472.     case lparen:        /* got a '(' or '[' */
  473.         ++ps.p_l_follow;    /* count parens to make Healy happy */
  474.         if (ps.want_blank && *token != '[' &&
  475.             (ps.last_token != ident || proc_calls_space
  476.           || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
  477.         *e_code++ = ' ';
  478.         if (ps.in_decl && !ps.block_init)
  479.         if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl) {
  480.             ps.dumped_decl_indent = 1;
  481.             sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  482.             e_code += strlen(e_code);
  483.         }
  484.         else {
  485.             while ((e_code - s_code) < dec_ind) {
  486.             check_size(code);
  487.             *e_code++ = ' ';
  488.             }
  489.             *e_code++ = token[0];
  490.         }
  491.         else
  492.         *e_code++ = token[0];
  493.         ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
  494.         if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent
  495.             && ps.paren_indents[0] < 2 * ps.ind_size)
  496.         ps.paren_indents[0] = 2 * ps.ind_size;
  497.         ps.want_blank = false;
  498.         if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
  499.         /*
  500.          * this is a kluge to make sure that declarations will be
  501.          * aligned right if proc decl has an explicit type on it, i.e.
  502.          * "int a(x) {..."
  503.          */
  504.         parse(semicolon);    /* I said this was a kluge... */
  505.         ps.in_or_st = false;    /* turn off flag for structure decl or
  506.                      * initialization */
  507.         }
  508.         if (ps.sizeof_keyword)
  509.         ps.sizeof_mask |= 1 << ps.p_l_follow;
  510.         break;
  511.  
  512.     case rparen:        /* got a ')' or ']' */
  513.         if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) {
  514.         ps.last_u_d = true;
  515.         ps.cast_mask &= (1 << ps.p_l_follow) - 1;
  516.         }
  517.         ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
  518.         if (--ps.p_l_follow < 0) {
  519.         ps.p_l_follow = 0;
  520.         diag(0, "Extra %c", *token);
  521.         }
  522.         if (e_code == s_code)    /* if the paren starts the line */
  523.         ps.paren_level = ps.p_l_follow;    /* then indent it */
  524.  
  525.         *e_code++ = token[0];
  526.         ps.want_blank = true;
  527.  
  528.         if (sp_sw && (ps.p_l_follow == 0)) {    /* check for end of if
  529.                              * (...), or some such */
  530.         sp_sw = false;
  531.         force_nl = true;/* must force newline after if */
  532.         ps.last_u_d = true;    /* inform lexi that a following
  533.                      * operator is unary */
  534.         ps.in_stmt = false;    /* dont use stmt continuation
  535.                      * indentation */
  536.  
  537.         parse(hd_type);    /* let parser worry about if, or whatever */
  538.         }
  539.         ps.search_brace = btype_2;    /* this should insure that constructs
  540.                      * such as main(){...} and int[]{...}
  541.                      * have their braces put in the right
  542.                      * place */
  543.         break;
  544.  
  545.     case unary_op:        /* this could be any unary operation */
  546.         if (ps.want_blank)
  547.         *e_code++ = ' ';
  548.  
  549.         if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname) {
  550.         sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  551.         ps.dumped_decl_indent = 1;
  552.         e_code += strlen(e_code);
  553.         }
  554.         else {
  555.         char       *res = token;
  556.  
  557.         if (ps.in_decl && !ps.block_init) {    /* if this is a unary op
  558.                              * in a declaration, we
  559.                              * should indent this
  560.                              * token */
  561.             for (i = 0; token[i]; ++i);    /* find length of token */
  562.             while ((e_code - s_code) < (dec_ind - i)) {
  563.             check_size(code);
  564.             *e_code++ = ' ';    /* pad it */
  565.             }
  566.         }
  567.         if (troff && token[0] == '-' && token[1] == '>')
  568.             res = "\\(->";
  569.         for (t_ptr = res; *t_ptr; ++t_ptr) {
  570.             check_size(code);
  571.             *e_code++ = *t_ptr;
  572.         }
  573.         }
  574.         ps.want_blank = false;
  575.         break;
  576.  
  577.     case binary_op:    /* any binary operation */
  578.     do_binary:
  579.         if (ps.want_blank)
  580.         *e_code++ = ' ';
  581.         {
  582.         char       *res = token;
  583.  
  584.         if (troff)
  585.             switch (token[0]) {
  586.             case '<':
  587.             if (token[1] == '=')
  588.                 res = "\\(<=";
  589.             break;
  590.             case '>':
  591.             if (token[1] == '=')
  592.                 res = "\\(>=";
  593.             break;
  594.             case '!':
  595.             if (token[1] == '=')
  596.                 res = "\\(!=";
  597.             break;
  598.             case '|':
  599.             if (token[1] == '|')
  600.                 res = "\\(br\\(br";
  601.             else if (token[1] == 0)
  602.                 res = "\\(br";
  603.             break;
  604.             }
  605.         for (t_ptr = res; *t_ptr; ++t_ptr) {
  606.             check_size(code);
  607.             *e_code++ = *t_ptr;    /* move the operator */
  608.         }
  609.         }
  610.         ps.want_blank = true;
  611.         break;
  612.  
  613.     case postop:        /* got a trailing ++ or -- */
  614.         *e_code++ = token[0];
  615.         *e_code++ = token[1];
  616.         ps.want_blank = true;
  617.         break;
  618.  
  619.     case question:        /* got a ? */
  620.         squest++;        /* this will be used when a later colon
  621.                  * appears so we can distinguish the
  622.                  * <c>?<n>:<n> construct */
  623.         if (ps.want_blank)
  624.         *e_code++ = ' ';
  625.         *e_code++ = '?';
  626.         ps.want_blank = true;
  627.         break;
  628.  
  629.     case casestmt:        /* got word 'case' or 'default' */
  630.         scase = true;    /* so we can process the later colon properly */
  631.         goto copy_id;
  632.  
  633.     case colon:        /* got a ':' */
  634.         if (squest > 0) {    /* it is part of the <c>?<n>: <n> construct */
  635.         --squest;
  636.         if (ps.want_blank)
  637.             *e_code++ = ' ';
  638.         *e_code++ = ':';
  639.         ps.want_blank = true;
  640.         break;
  641.         }
  642.         if (ps.in_decl) {
  643.         *e_code++ = ':';
  644.         ps.want_blank = false;
  645.         break;
  646.         }
  647.         ps.in_stmt = false;    /* seeing a label does not imply we are in a
  648.                  * stmt */
  649.         for (t_ptr = s_code; *t_ptr; ++t_ptr)
  650.         *e_lab++ = *t_ptr;    /* turn everything so far into a label */
  651.         e_code = s_code;
  652.         *e_lab++ = ':';
  653.         *e_lab++ = ' ';
  654.         *e_lab = '\0';
  655.  
  656.         force_nl = ps.pcase = scase;    /* ps.pcase will be used by
  657.                          * dump_line to decide how to
  658.                          * indent the label. force_nl
  659.                          * will force a case n: to be
  660.                          * on a line by itself */
  661.         scase = false;
  662.         ps.want_blank = false;
  663.         break;
  664.  
  665.     case semicolon:    /* got a ';' */
  666.         ps.in_or_st = false;/* we are not in an initialization or
  667.                  * structure declaration */
  668.         scase = false;    /* these will only need resetting in a error */
  669.         squest = 0;
  670.         if (ps.last_token == rparen)
  671.         ps.in_parameter_declaration = 0;
  672.         ps.cast_mask = 0;
  673.         ps.sizeof_mask = 0;
  674.         ps.block_init = 0;
  675.         ps.block_init_level = 0;
  676.         ps.just_saw_decl--;
  677.  
  678.         if (ps.in_decl && s_code == e_code && !ps.block_init)
  679.         while ((e_code - s_code) < (dec_ind - 1)) {
  680.             check_size(code);
  681.             *e_code++ = ' ';
  682.         }
  683.  
  684.         ps.in_decl = (ps.dec_nest > 0);    /* if we were in a first level
  685.                          * structure declaration, we
  686.                          * arent any more */
  687.  
  688.         if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
  689.  
  690.         /*
  691.          * This should be true iff there were unbalanced parens in the
  692.          * stmt.  It is a bit complicated, because the semicolon might
  693.          * be in a for stmt
  694.          */
  695.         diag(1, "Unbalanced parens");
  696.         ps.p_l_follow = 0;
  697.         if (sp_sw) {    /* this is a check for a if, while, etc. with
  698.                  * unbalanced parens */
  699.             sp_sw = false;
  700.             parse(hd_type);    /* dont lose the if, or whatever */
  701.         }
  702.         }
  703.         *e_code++ = ';';
  704.         ps.want_blank = true;
  705.         ps.in_stmt = (ps.p_l_follow > 0);    /* we are no longer in the
  706.                          * middle of a stmt */
  707.  
  708.         if (!sp_sw) {    /* if not if for (;;) */
  709.         parse(semicolon);    /* let parser know about end of stmt */
  710.         force_nl = true;/* force newline after a end of stmt */
  711.         }
  712.         break;
  713.  
  714.     case lbrace:        /* got a '{' */
  715.         ps.in_stmt = false;    /* dont indent the {} */
  716.         if (!ps.block_init)
  717.         force_nl = true;/* force other stuff on same line as '{' onto
  718.                  * new line */
  719.         else if (ps.block_init_level <= 0)
  720.         ps.block_init_level = 1;
  721.         else
  722.         ps.block_init_level++;
  723.  
  724.         if (s_code != e_code && !ps.block_init) {
  725.         if (!btype_2) {
  726.             dump_line();
  727.             ps.want_blank = false;
  728.         }
  729.         else if (ps.in_parameter_declaration && !ps.in_or_st) {
  730.             ps.i_l_follow = 0;
  731.             dump_line();
  732.             ps.want_blank = false;
  733.         }
  734.         }
  735.         if (ps.in_parameter_declaration)
  736.         prefix_blankline_requested = 0;
  737.  
  738.         if (ps.p_l_follow > 0) {    /* check for preceeding unbalanced
  739.                      * parens */
  740.         diag(1, "Unbalanced parens");
  741.         ps.p_l_follow = 0;
  742.         if (sp_sw) {    /* check for unclosed if, for, etc. */
  743.             sp_sw = false;
  744.             parse(hd_type);
  745.             ps.ind_level = ps.i_l_follow;
  746.         }
  747.         }
  748.         if (s_code == e_code)
  749.         ps.ind_stmt = false;    /* dont put extra indentation on line
  750.                      * with '{' */
  751.         if (ps.in_decl && ps.in_or_st) {    /* this is either a structure
  752.                          * declaration or an init */
  753.         di_stack[ps.dec_nest++] = dec_ind;
  754.         /* ?        dec_ind = 0; */
  755.         }
  756.         else {
  757.         ps.decl_on_line = false;    /* we cant be in the middle of
  758.                          * a declaration, so dont do
  759.                          * special indentation of
  760.                          * comments */
  761.         if (blanklines_after_declarations_at_proctop
  762.             && ps.in_parameter_declaration)
  763.             postfix_blankline_requested = 1;
  764.         ps.in_parameter_declaration = 0;
  765.         }
  766.         dec_ind = 0;
  767.         parse(lbrace);    /* let parser know about this */
  768.         if (ps.want_blank)    /* put a blank before '{' if '{' is not at
  769.                  * start of line */
  770.         *e_code++ = ' ';
  771.         ps.want_blank = false;
  772.         *e_code++ = '{';
  773.         ps.just_saw_decl = 0;
  774.         break;
  775.  
  776.     case rbrace:        /* got a '}' */
  777.         if (ps.p_stack[ps.tos] == decl && !ps.block_init)    /* semicolons can be
  778.                                  * omitted in
  779.                                  * declarations */
  780.         parse(semicolon);
  781.         if (ps.p_l_follow) {/* check for unclosed if, for, else. */
  782.         diag(1, "Unbalanced parens");
  783.         ps.p_l_follow = 0;
  784.         sp_sw = false;
  785.         }
  786.         ps.just_saw_decl = 0;
  787.         ps.block_init_level--;
  788.         if (s_code != e_code && !ps.block_init) {    /* '}' must be first on
  789.                              * line */
  790.         if (verbose)
  791.             diag(0, "Line broken");
  792.         dump_line();
  793.         }
  794.         *e_code++ = '}';
  795.         ps.want_blank = true;
  796.         ps.in_stmt = ps.ind_stmt = false;
  797.         if (ps.dec_nest > 0) {    /* we are in multi-level structure
  798.                      * declaration */
  799.         dec_ind = di_stack[--ps.dec_nest];
  800.         if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
  801.             ps.just_saw_decl = 2;
  802.         ps.in_decl = true;
  803.         }
  804.         prefix_blankline_requested = 0;
  805.         parse(rbrace);    /* let parser know about this */
  806.         ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
  807.         && ps.il[ps.tos] >= ps.ind_level;
  808.         if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
  809.         postfix_blankline_requested = 1;
  810.         break;
  811.  
  812.     case swstmt:        /* got keyword "switch" */
  813.         sp_sw = true;
  814.         hd_type = swstmt;    /* keep this for when we have seen the
  815.                  * expression */
  816.         goto copy_id;    /* go move the token into buffer */
  817.  
  818.     case sp_paren:        /* token is if, while, for */
  819.         sp_sw = true;    /* the interesting stuff is done after the
  820.                  * expression is scanned */
  821.         hd_type = (*token == 'i' ? ifstmt :
  822.                (*token == 'w' ? whilestmt : forstmt));
  823.  
  824.         /*
  825.          * remember the type of header for later use by parser
  826.          */
  827.         goto copy_id;    /* copy the token into line */
  828.  
  829.     case sp_nparen:    /* got else, do */
  830.         ps.in_stmt = false;
  831.         if (*token == 'e') {
  832.         if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
  833.             if (verbose)
  834.             diag(0, "Line broken");
  835.             dump_line();/* make sure this starts a line */
  836.             ps.want_blank = false;
  837.         }
  838.         force_nl = true;/* also, following stuff must go onto new line */
  839.         last_else = 1;
  840.         parse(elselit);
  841.         }
  842.         else {
  843.         if (e_code != s_code) {    /* make sure this starts a line */
  844.             if (verbose)
  845.             diag(0, "Line broken");
  846.             dump_line();
  847.             ps.want_blank = false;
  848.         }
  849.         force_nl = true;/* also, following stuff must go onto new line */
  850.         last_else = 0;
  851.         parse(dolit);
  852.         }
  853.         goto copy_id;    /* move the token into line */
  854.  
  855.     case decl:        /* we have a declaration type (int, register,
  856.                  * etc.) */
  857.         parse(decl);    /* let parser worry about indentation */
  858.         if (ps.last_token == rparen && ps.tos <= 1) {
  859.         ps.in_parameter_declaration = 1;
  860.         if (s_code != e_code) {
  861.             dump_line();
  862.             ps.want_blank = 0;
  863.         }
  864.         }
  865.         if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
  866.         ps.ind_level = ps.i_l_follow = 1;
  867.         ps.ind_stmt = 0;
  868.         }
  869.         ps.in_or_st = true;    /* this might be a structure or initialization
  870.                  * declaration */
  871.         ps.in_decl = ps.decl_on_line = true;
  872.         if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
  873.         ps.just_saw_decl = 2;
  874.         prefix_blankline_requested = 0;
  875.         for (i = 0; token[i++];);    /* get length of token */
  876.  
  877.         /*
  878.          * dec_ind = e_code - s_code + (ps.decl_indent>i ? ps.decl_indent
  879.          * : i);
  880.          */
  881.         dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
  882.         goto copy_id;
  883.  
  884.     case ident:        /* got an identifier or constant */
  885.         if (ps.in_decl) {    /* if we are in a declaration, we must indent
  886.                  * identifier */
  887.         if (ps.want_blank)
  888.             *e_code++ = ' ';
  889.         ps.want_blank = false;
  890.         if (is_procname == 0 || !procnames_start_line) {
  891.             if (!ps.block_init)
  892.             if (troff && !ps.dumped_decl_indent) {
  893.                 sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
  894.                 ps.dumped_decl_indent = 1;
  895.                 e_code += strlen(e_code);
  896.             }
  897.             else
  898.                 while ((e_code - s_code) < dec_ind) {
  899.                 check_size(code);
  900.                 *e_code++ = ' ';
  901.                 }
  902.         }
  903.         else {
  904.             if (dec_ind && s_code != e_code)
  905.             dump_line();
  906.             dec_ind = 0;
  907.             ps.want_blank = false;
  908.         }
  909.         }
  910.         else if (sp_sw && ps.p_l_follow == 0) {
  911.         sp_sw = false;
  912.         force_nl = true;
  913.         ps.last_u_d = true;
  914.         ps.in_stmt = false;
  915.         parse(hd_type);
  916.         }
  917.     copy_id:
  918.         if (ps.want_blank)
  919.         *e_code++ = ' ';
  920.         if (troff && ps.its_a_keyword) {
  921.         e_code = chfont(&bodyf, &keywordf, e_code);
  922.         for (t_ptr = token; *t_ptr; ++t_ptr) {
  923.             check_size(code);
  924.             *e_code++ = keywordf.allcaps && islower(*t_ptr)
  925.             ? toupper(*t_ptr) : *t_ptr;
  926.         }
  927.         e_code = chfont(&keywordf, &bodyf, e_code);
  928.         }
  929.         else
  930.         for (t_ptr = token; *t_ptr; ++t_ptr) {
  931.             check_size(code);
  932.             *e_code++ = *t_ptr;
  933.         }
  934.         ps.want_blank = true;
  935.         break;
  936.  
  937.     case period:        /* treat a period kind of like a binary
  938.                  * operation */
  939.         *e_code++ = '.';    /* move the period into line */
  940.         ps.want_blank = false;    /* dont put a blank after a period */
  941.         break;
  942.  
  943.     case comma:
  944.         ps.want_blank = (s_code != e_code);    /* only put blank after comma
  945.                          * if comma does not start the
  946.                          * line */
  947.         if (ps.in_decl && is_procname == 0 && !ps.block_init)
  948.         while ((e_code - s_code) < (dec_ind - 1)) {
  949.             check_size(code);
  950.             *e_code++ = ' ';
  951.         }
  952.  
  953.         *e_code++ = ',';
  954.         if (ps.p_l_follow == 0) {
  955.         if (ps.block_init_level <= 0)
  956.             ps.block_init = 0;
  957.         if (break_comma && !ps.leave_comma)
  958.             force_nl = true;
  959.         }
  960.         break;
  961.  
  962.     case preesc:        /* got the character '#' */
  963.         if ((s_com != e_com) ||
  964.             (s_lab != e_lab) ||
  965.             (s_code != e_code))
  966.         dump_line();
  967.         *e_lab++ = '#';    /* move whole line to 'label' buffer */
  968.         {
  969.         int         in_comment = 0;
  970.         int         com_start = 0;
  971.         char        quote = 0;
  972.         int         com_end = 0;
  973.  
  974.         while (*buf_ptr != '\n' || in_comment) {
  975.             check_size(lab);
  976.             *e_lab = *buf_ptr++;
  977.             if (buf_ptr >= buf_end)
  978.             fill_buffer();
  979.             switch (*e_lab++) {
  980.             case BACKSLASH:
  981.             if (troff)
  982.                 *e_lab++ = BACKSLASH;
  983.             if (!in_comment) {
  984.                 *e_lab++ = *buf_ptr++;
  985.                 if (buf_ptr >= buf_end)
  986.                 fill_buffer();
  987.             }
  988.             break;
  989.             case '/':
  990.             if (*buf_ptr == '*' && !in_comment && !quote) {
  991.                 in_comment = 1;
  992.                 *e_lab++ = *buf_ptr++;
  993.                 com_start = e_lab - s_lab - 2;
  994.             }
  995.             break;
  996.             case '"':
  997.             if (quote == '"')
  998.                 quote = 0;
  999.             break;
  1000.             case '\'':
  1001.             if (quote == '\'')
  1002.                 quote = 0;
  1003.             break;
  1004.             case '*':
  1005.             if (*buf_ptr == '/' && in_comment) {
  1006.                 in_comment = 0;
  1007.                 *e_lab++ = *buf_ptr++;
  1008.                 com_end = e_lab - s_lab;
  1009.             }
  1010.             break;
  1011.             }
  1012.         }
  1013.  
  1014.         while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1015.             e_lab--;
  1016.         if (e_lab - s_lab == com_end && bp_save == 0) {    /* comment on
  1017.                                  * preprocessor line */
  1018.             if (sc_end == 0)    /* if this is the first comment, we
  1019.                      * must set up the buffer */
  1020.             sc_end = &(save_com[0]);
  1021.             else {
  1022.             *sc_end++ = '\n';    /* add newline between
  1023.                          * comments */
  1024.             *sc_end++ = ' ';
  1025.             --line_no;
  1026.             }
  1027.             bcopy(s_lab + com_start, sc_end, com_end - com_start);
  1028.             sc_end += com_end - com_start;
  1029.             if (sc_end >= &save_com[sc_size])
  1030.             abort();
  1031.             e_lab = s_lab + com_start;
  1032.             while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1033.             e_lab--;
  1034.             bp_save = buf_ptr;    /* save current input buffer */
  1035.             be_save = buf_end;
  1036.             buf_ptr = save_com;    /* fix so that subsequent calls to
  1037.                      * lexi will take tokens out of
  1038.                      * save_com */
  1039.             *sc_end++ = ' ';    /* add trailing blank, just in case */
  1040.             buf_end = sc_end;
  1041.             sc_end = 0;
  1042.         }
  1043.         *e_lab = '\0';    /* null terminate line */
  1044.         ps.pcase = false;
  1045.         }
  1046.  
  1047.         if (strncmp(s_lab, "#if", 3) == 0) {
  1048.         if (blanklines_around_conditional_compilation) {
  1049.             register    c;
  1050.             prefix_blankline_requested++;
  1051.             while ((c = getc(input)) == '\n');
  1052.             ungetc(c, input);
  1053.         }
  1054.         if (ifdef_level < sizeof state_stack / sizeof state_stack[0]) {
  1055.             match_state[ifdef_level].tos = -1;
  1056.             state_stack[ifdef_level++] = ps;
  1057.         }
  1058.         else
  1059.             diag(1, "#if stack overflow");
  1060.         }
  1061.         else if (strncmp(s_lab, "#else", 5) == 0)
  1062.         if (ifdef_level <= 0)
  1063.             diag(1, "Unmatched #else");
  1064.         else {
  1065.             match_state[ifdef_level - 1] = ps;
  1066.             ps = state_stack[ifdef_level - 1];
  1067.         }
  1068.         else if (strncmp(s_lab, "#endif", 6) == 0) {
  1069.         if (ifdef_level <= 0)
  1070.             diag(1, "Unmatched #endif");
  1071.         else {
  1072.             ifdef_level--;
  1073.  
  1074. #ifdef undef
  1075.             /*
  1076.              * This match needs to be more intelligent before the
  1077.              * message is useful
  1078.              */
  1079.             if (match_state[ifdef_level].tos >= 0
  1080.               && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
  1081.             diag(0, "Syntactically inconsistant #ifdef alternatives.");
  1082. #endif
  1083.         }
  1084.         if (blanklines_around_conditional_compilation) {
  1085.             postfix_blankline_requested++;
  1086.             n_real_blanklines = 0;
  1087.         }
  1088.         }
  1089.         break;        /* subsequent processing of the newline
  1090.                  * character will cause the line to be printed */
  1091.  
  1092.     case comment:        /* we have gotten a /*  this is a biggie */
  1093.     proc_comment:
  1094.         if (flushed_nl) {    /* we should force a broken line here */
  1095.         flushed_nl = false;
  1096.         dump_line();
  1097.         ps.want_blank = false;    /* dont insert blank at line start */
  1098.         force_nl = false;
  1099.         }
  1100.         pr_comment();
  1101.         break;
  1102.     }            /* end of big switch stmt */
  1103.  
  1104.     *e_code = '\0';        /* make sure code section is null terminated */
  1105.     if (type_code != comment && type_code != newline && type_code != preesc)
  1106.         ps.last_token = type_code;
  1107.     }                /* end of main while (1) loop */
  1108. };
  1109.  
  1110. /*
  1111.  * copy input file to backup file if in_name is /blah/blah/blah/file, then
  1112.  * backup file will be ".Bfile" then make the backup file the input and
  1113.  * original input file the output
  1114.  */
  1115.  
  1116. bakcopy()
  1117. {
  1118.     int         n,
  1119.                 bakchn;
  1120.     char        buff[8 * 1024];
  1121.     register char *p;
  1122.  
  1123.     /* construct file name .Bfile */
  1124.     
  1125. #ifdef MSDOS
  1126.     strcpy(tmpstr, in_name);
  1127.  
  1128.     /* RjR: change '\' to '/' */
  1129.     for (p = tmpstr; *p; p++)
  1130.         if (p=='\\')
  1131.             *p='/';
  1132.  
  1133.     /* kill the '.ext' part */
  1134.     for (p = tmpstr; *p!='.' && *p!='\0'; p++)
  1135.         ;
  1136.     *p='\0';
  1137.     
  1138.     for (p = tmpstr; *p; p++);    /* skip to end of string */
  1139.     while (p > tmpstr && *p != '/')    /* find last '/' */
  1140.     p--;
  1141.     if (*p == '/')
  1142.     p++;
  1143.     sprintf(bakfile, "%s.BAK", p);
  1144. #else
  1145.     for (p = in_name; *p; p++);    /* skip to end of string */
  1146.     while (p > in_name && *p != '/')    /* find last '/' */
  1147.     p--;
  1148.     if (*p == '/')
  1149.     p++;
  1150.     sprintf(bakfile, "%s.BAK", p);
  1151. #endif
  1152.  
  1153.     /* copy in_name to backup file */
  1154.     bakchn = creat(bakfile, 0600);
  1155.     if (bakchn < 0) {
  1156.     fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
  1157.     exit(1);
  1158.     }
  1159.     while (n = read(fileno(input), buff, sizeof buff))
  1160.     if (write(bakchn, buff, n) != n) {
  1161.         fprintf(stderr, "indent: error writing backup file \"%s\"\n",
  1162.             bakfile);
  1163.         exit(1);
  1164.     }
  1165.     if (n < 0) {
  1166.     fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
  1167.     exit(1);
  1168.     }
  1169.     close(bakchn);
  1170.     fclose(input);
  1171.  
  1172.     /* re-open backup file as the input file */
  1173.     input = fopen(bakfile, "r");
  1174.     if (input == 0) {
  1175.     fprintf(stderr, "indent: can't re-open backup file\n");
  1176.     exit(1);
  1177.     }
  1178.     /* now the original input file will be the output */
  1179.     output = fopen(in_name, "w");
  1180.     if (output == 0) {
  1181.     fprintf(stderr, "indent: can't create %s\n", in_name);
  1182.     unlink(bakfile);
  1183.     exit(1);
  1184.     }
  1185. }
  1186.